package com.ikas.ai.server.module.instance.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkInstanceStepCostDao;
import com.ikas.ai.server.module.instance.model.DorisWorkFlowInstance;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStep;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStepCost;
import com.ikas.ai.utils.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DorisWorkInstanceStepCostService extends ServiceImpl<DorisWorkInstanceStepCostDao, DorisWorkInstanceStepCost> {

    @Autowired
    DorisWorkInstanceStepService dorisWorkInstanceStepService;
    @Autowired
    DorisWorkFlowInstanceService dorisWorkFlowInstanceService;


    @Value("${work-instance.step.delay.max-length:100}")
    Integer maxStepDelayLength;

    /**
     * @param machineNo
     * @param step  当前step的meteCode
     */
    @Transactional(rollbackFor = Exception.class)
    public void computeAvgDelay(String machineNo, DorisWorkInstanceStep step) {
        if (machineNo == null) {
            return;
        }
        DorisWorkInstanceStepCost one = getOne(
                new LambdaQueryWrapper<DorisWorkInstanceStepCost>()
                        .eq(DorisWorkInstanceStepCost::getMachineNo, machineNo)
                        .eq(DorisWorkInstanceStepCost::getWfName, step.getWfName())
                        .eq(DorisWorkInstanceStepCost::getStepName, step.getStepName())
        );
        //如果为空，新建一个对象，并新建一个数组并放入当前delay时间
        if (one == null) {
            synchronized (this) {
                one = getOne(
                        new LambdaQueryWrapper<DorisWorkInstanceStepCost>()
                                .eq(DorisWorkInstanceStepCost::getMachineNo, machineNo)
                                .eq(DorisWorkInstanceStepCost::getWfName, step.getWfName())
                                .eq(DorisWorkInstanceStepCost::getStepName, step.getStepName())
                );
                if (one == null) {
                    one = new DorisWorkInstanceStepCost().setMachineNo(machineNo).setWfName(step.getWfName()).setStepName(step.getStepName()).setMeteCode(step.getMeteCode());
                    List<Long> delayArray = new ArrayList<>();
                    delayArray.add(step.getDelay());
                    one.setDelayArray(delayArray);
                    one.setAvgDelay(step.getDelay());
                    save(one);
                } else {
                    one = dealWithDelay(step.getDelay(), one);
                    one.setUpdateTime(new Date());
                    save(one);
                }
            }
        } else {
            one = dealWithDelay(step.getDelay(), one);
            one.setUpdateTime(new Date());
            save(one);
        }
        //更新step表avgTime
        step.setAvgDelay(one.getAvgDelay());
        step.setUpdateTime(new Date());
        dorisWorkInstanceStepService.updateById(step);
    }

    private DorisWorkInstanceStepCost dealWithDelay(Long costTime, DorisWorkInstanceStepCost one) {
        if (costTime == null) {
            return one;
        }
        if (one.getDelayArray() == null) {
            one.setDelayArray(new ArrayList<>());
        }
        LinkedList<Long> delayArray = new LinkedList<>(one.getDelayArray());
        if (delayArray.size() < maxStepDelayLength) {
            //DO NOTHING
            delayArray.addFirst(costTime);
        } else if (delayArray.size() > maxStepDelayLength) {
            Integer defaultSize = delayArray.size();
            for (int k = 0; k <= defaultSize - maxStepDelayLength; k++) {
                delayArray.pollLast();
            }
            delayArray.addFirst(costTime);
        } else {
            delayArray.removeLast();
            delayArray.addFirst(costTime);
        }
        one.setDelayArray(delayArray);
        Long sum = 0L;
        for (Long delayElement : delayArray) {
            sum += delayElement;
        }
        Long avgDelay = 0L;
        if (sum != 0) {
            avgDelay = sum / delayArray.size();
        }
        one.setAvgDelay(avgDelay);
        return one;
    }
}
